package com.yanqu.road.server.manger.activity.hell;

import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.hell.*;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.entity.enums.eSystemId;
import com.yanqu.road.logic.bussiness.activity.HellBusiness;
import com.yanqu.road.pb.activity.HellProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.hell.HellModule;
import com.yanqu.road.server.manger.ServerLanguageMgr;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class HellMgr extends TempMgr {

    private static RandomHelper randomHelper = new RandomHelper();

    private static ActivityInfo activityInfo;

    private static Map<Integer, HellNpcConfig> npcMap = new ConcurrentHashMap<>();
    private static Map<Integer, HellQualityConfig> qualityMap = new ConcurrentHashMap<>();
    //qualityId eventType id
    private static Map<Integer, Map<Integer,Map<Integer, HellEventConfig>>> eventMap = new ConcurrentHashMap<>();
    private static Map<Integer, HellAgeConfig> ageMap = new ConcurrentHashMap<>();

    //阎王簿每一页最多多少人
    private static int HELL_NPC_LIMIT = 60;

    //积分道具
    private static int HELL_SCORE_ITEM_ID = 101984;
    //令签道具
    private static int HELL_SEARCH_ITEM_ID = 120589;
    //一次使用道具
    private static int HELL_COST_ONE = 1;
    //一键一次使用道具数量
    private static int HELL_COST_ONEKEY = 9;
    //一键的vip等级要求
    private static int HELL_ONEKEY_VIP = 8;
    //一键的断案十次开启条件(功德值>=)
    private static int HELL_ONEKEY_SCORE = 1000;

    public static int getOneKeyVipLimit(){
        return HELL_ONEKEY_VIP;
    }

    public static int getOneKeyScoreLimit(){
        return HELL_ONEKEY_SCORE;
    }

    public static int getHellNpcLimit(){
        return HELL_NPC_LIMIT;
    }

    public static int getHellScoreItemId(){
        return HELL_SCORE_ITEM_ID;
    }

    public static int getHellSearchItemId(){
        return HELL_SEARCH_ITEM_ID;
    }

    public static String getHellSearchCost(int type){
        if(type == 1){
            return HELL_SEARCH_ITEM_ID + "=" + HELL_COST_ONE;
        }else if(type == 2){
            return HELL_SEARCH_ITEM_ID + "=" + HELL_COST_ONEKEY;
        }
        return "";
    }

    public static int getQualityReward(int qualityId){
        HellQualityConfig hellQualityConfig = qualityMap.get(qualityId);
        if(hellQualityConfig != null){
            return hellQualityConfig.getRewards();
        }
        return 0;
    }

    public static List<HellNpc> hellCutLaw(int type){
        List<HellNpc> npcList = new ArrayList<>();
        if(type == 1){
            npcList.add(makeOneNpc());
        }else if(type == 2){
            for(int i = 10;i > 0 ; i--){
                npcList.add(makeOneNpc());
            }
        }
        return npcList;
    }

    private static HellNpc makeOneNpc(){
        HellNpc npc = new HellNpc();
        HellNpcConfig npcConfig = randomNpc();
        HellAgeConfig ageConfig = randomAge();
        HellQualityConfig qualityConfig = randomQuality();
        npc.setNpcId(npcConfig.getNpcId());
        npc.setAgeId(ageConfig.getId());
        npc.setQualityId(qualityConfig.getId());
        Map<Integer,List<String>> eventMap = randomAllEvent(qualityConfig,ageConfig);
        npc.setEventMap(eventMap);
        npc.setTime(System.currentTimeMillis());
        return npc;
    }

    private static HellNpcConfig randomNpc(){
        HellNpcConfig randomNpc = null;
        int totalWeight = 0;
        for (HellNpcConfig npc : npcMap.values()) {
            int weight = npc.getWeight();
            totalWeight += weight;
        }
        int randomNum = randomHelper.next(0, totalWeight);
        for (HellNpcConfig npc : npcMap.values()) {
            int value = npc.getWeight();
            if (randomNum < value) {
                randomNpc = npc;
                break;
            }
            randomNum -= value;
        }
        return randomNpc;
    }

    private static HellAgeConfig randomAge(){
        HellAgeConfig randomAge = null;
        int totalWeight = 0;
        for (HellAgeConfig age : ageMap.values()) {
            int weight = age.getWeight();
            totalWeight += weight;
        }
        int randomNum = randomHelper.next(0, totalWeight);
        for (HellAgeConfig age : ageMap.values()) {
            int value = age.getWeight();
            if (randomNum < value) {
                randomAge = age;
                break;
            }
            randomNum -= value;
        }
        return randomAge;
    }

    public static HellQualityConfig randomQuality(){
        HellQualityConfig randomQuality = null;
        int totalWeight = 0;
        for (HellQualityConfig quality : qualityMap.values()) {
            int weight = quality.getWeight();
            totalWeight += weight;
        }
        int randomNum = randomHelper.next(0, totalWeight);
        for (HellQualityConfig quality : qualityMap.values()) {
            int value = quality.getWeight();
            if (randomNum < value) {
                randomQuality = quality;
                break;
            }
            randomNum -= value;
        }
        return randomQuality;
    }

    public static HellEventConfig randomOneEvent(Map<Integer, HellEventConfig> eventConfigMap){
        List<HellEventConfig> randomMap = new ArrayList<>(eventConfigMap.values());
        if(randomMap.size() == 0){
            return null;
        }
        int totalWeight = randomMap.size();
        int randomNum = randomHelper.next(0, totalWeight);
        return randomMap.get(randomNum);
    }

    private static int randomEventAge(Map<Integer,Integer> ageMap){
        int randomAge = 0;
        int totalWeight = 0;
        for (Integer age : ageMap.keySet()) {
            int weight = ageMap.get(age);
            totalWeight += weight;
        }
        int randomNum = randomHelper.next(0, totalWeight);
        for (Integer age : ageMap.keySet()) {
            int value = ageMap.get(age);
            if (randomNum < value) {
                randomAge = age;
                break;
            }
            randomNum -= value;
        }
        return randomAge;
    }

    private static List<Integer> randomEventAgeList(int times, int minAge,int maxAge){
        List<Integer> ageList = new ArrayList<>();
        Map<Integer,Integer> ageMap = new ConcurrentHashMap<>();
        for(int i = minAge; i < maxAge ; i++){
            ageMap.put(i,1);
        }
        for(int i = 0;i < times;i++){
            int randomAge = randomEventAge(ageMap);
            ageMap.remove(randomAge);
            ageList.add(randomAge);
        }
        Collections.sort(ageList);
        return ageList;
    }

    //随机生平词条年龄
    private static Map<Integer,List<Integer>> randomEventAgeMap(HellAgeConfig ageConfig){
        Map<Integer,List<Integer>> ageMap = new ConcurrentHashMap<>();
        List<Integer> tempAgeList = StringUtils.stringToIntegerList(ageConfig.getAge(),",");
        int ageMin = tempAgeList.get(0);
        int ageMax = tempAgeList.get(1);
        int deathAge = randomHelper.next(ageMin, ageMax);
        int tempAge = 0;
        Map<Integer, Integer> needEventMap = ageConfig.getNeedEventMap();
        int tempAllYear = 0;
        for(int eventType : needEventMap.keySet()){
            tempAllYear += needEventMap.get(eventType);
        }
        for(int eventType : needEventMap.keySet()){
            int times = needEventMap.get(eventType);
            if(times == 0)continue;
            //死亡事件
            if(eventType == 4){
                List<Integer> ageList = new ArrayList<>();
                ageList.add(deathAge);
                ageMap.put(eventType,ageList);
            }else{
                tempAllYear = tempAllYear - times;
                List<Integer> ageList = randomEventAgeList(times,tempAge + 1,deathAge - tempAllYear);
                tempAge = ageList.get(ageList.size() - 1);
                ageMap.put(eventType,ageList);
            }
        }
        return ageMap;
    }

    //随机生平词条
    public static Map<Integer,List<String>> randomAllEvent(HellQualityConfig quality,HellAgeConfig age){
        //随机出来每个事件的年龄 eventType 对应事件个数
        Map<Integer,List<Integer>> ageMap = randomEventAgeMap(age);
        Map<Integer,List<String>> randomEvent = new ConcurrentHashMap<>();
        Map<Integer,Map<Integer, HellEventConfig>> qualityEventMap = eventMap.get(quality.getId());
        Map<Integer, Integer> eventMap = age.getNeedEventMap();
        for(int eventType : eventMap.keySet()){
            if(!randomEvent.containsKey(eventType)){
                randomEvent.put(eventType,new ArrayList<>());
            }
            Map<Integer, HellEventConfig> tempEventMap = new ConcurrentHashMap<>(qualityEventMap.get(eventType));
            int times = eventMap.get(eventType);
            for(int i = 0; i < times;i++){
                HellEventConfig randomOneEvent = randomOneEvent(tempEventMap);
                if(randomOneEvent != null){
                    tempEventMap.remove(randomOneEvent.getId());
                    randomEvent.get(eventType).add(randomOneEvent.getId() + "=" + ageMap.get(eventType).get(i));
                }else{
                    getLogger().error("地府断案配置错误，事件不够quality:"+ quality.getId() + ",eventId:"+ eventType + ",需要事件{},"+ "事件信息{}",age.getNeedEventMap(),new ArrayList<>(qualityEventMap.get(eventType).keySet()));
                }
            }
        }
        return randomEvent;
    }

    public static HellProto.HellConfigDataTemp.Builder getConfigDataTempBuilder(String language) {
        HellProto.HellConfigDataTemp.Builder builder = HellProto.HellConfigDataTemp.newBuilder();
        for(HellNpcConfig npcConfig : npcMap.values()){
            HellProto.HellNpcConfigTemp.Builder npcBuilder = HellProto.HellNpcConfigTemp.newBuilder();
            npcBuilder.setId(npcConfig.getNpcId());
            npcBuilder.setIcon(npcConfig.getIcon());
            npcBuilder.setName(ServerLanguageMgr.getContent(npcConfig.getName(), language));
            npcBuilder.setWeight(npcConfig.getWeight());
            builder.addNpc(npcBuilder);
        }
        for(HellQualityConfig qualityConfig : qualityMap.values()){
            HellProto.HellQualityConfigTemp.Builder qualityBuilder = HellProto.HellQualityConfigTemp.newBuilder();
            qualityBuilder.setId(qualityConfig.getId());
            qualityBuilder.setIcon(qualityConfig.getIcon());
            qualityBuilder.setRewards(qualityConfig.getRewards());
            qualityBuilder.setName(ServerLanguageMgr.getContent(qualityConfig.getName(), language));
            qualityBuilder.setPlaceName(ServerLanguageMgr.getContent(qualityConfig.getPlaceName(), language));
            qualityBuilder.setPlaceDesc(ServerLanguageMgr.getContent(qualityConfig.getPlaceDesc(), language));
            qualityBuilder.setWeight(qualityConfig.getWeight());
            builder.addQuality(qualityBuilder);
        }

        for(HellAgeConfig ageConfig : ageMap.values()){
            HellProto.HellAgeConfigTemp.Builder ageBuilder = HellProto.HellAgeConfigTemp.newBuilder();
            ageBuilder.setId(ageConfig.getId());
            ageBuilder.setEventNum(ageConfig.getEventNum());
            ageBuilder.setAge(ageConfig.getAge());
            ageBuilder.setWeight(ageConfig.getWeight());
            builder.addAge(ageBuilder);
        }

        for(Map<Integer,Map<Integer, HellEventConfig>> temp1Map : eventMap.values()){
            for(Map<Integer, HellEventConfig> temp2Map : temp1Map.values()){
                for(HellEventConfig eventConfig : temp2Map.values()){
                    HellProto.HellEventConfigTemp.Builder eventBuilder = HellProto.HellEventConfigTemp.newBuilder();
                    eventBuilder.setId(eventConfig.getId());
                    eventBuilder.setEventType(eventConfig.getEventType());
                    eventBuilder.setQualityId(eventConfig.getQualityId());
                    builder.addEvent(eventBuilder);
                }
            }
        }
        return builder;
    }

    @Override
    public boolean reloadData() throws Exception {
        return true;
    }

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return false;
    }

    public static void reloadActivityData() {
        getLogger().info("reload hell activity start");

        // 获取活动
        ActivityInfo tmpActivityInfo;
        List<ActivityInfo> openActivityInfoList = NormalActivityMgr.getOpenActivityInfoList(eActivityType.HellActivity.getValue());
        if (openActivityInfoList.size() <= 0) {
            getLogger().info("no hell activity in show time");
            return;
        }
        tmpActivityInfo = openActivityInfoList.get(0);

        Map<Integer, HellNpcConfig> tempNcpMap = HellBusiness.getHellNpcMap(tmpActivityInfo.getActivityId());
        Map<Integer, HellQualityConfig> tempQualityMap = HellBusiness.getHellQualityMap(tmpActivityInfo.getActivityId());
        Map<Integer, Map<Integer,Map<Integer, HellEventConfig>>> tempEventMap = HellBusiness.getHellEventMap(tmpActivityInfo.getActivityId());
        Map<Integer, HellAgeConfig> tempAgeMap = HellBusiness.getHellAgeMap(tmpActivityInfo.getActivityId());

        // 活动配置
        Map<String, ActivityConfig> activityConfigMap = NormalActivityMgr.getActivityConfigMap(tmpActivityInfo.getActivityId());
        if(activityConfigMap != null){
            if(activityConfigMap.containsKey("HELL_SCORE_ITEM_ID")){
                HELL_SCORE_ITEM_ID = activityConfigMap.get("HELL_SCORE_ITEM_ID").getIntValue();
            }
            if(activityConfigMap.containsKey("HELL_SEARCH_ITEM_ID")){
                HELL_SEARCH_ITEM_ID = activityConfigMap.get("HELL_SEARCH_ITEM_ID").getIntValue();
            }
            if(activityConfigMap.containsKey("HELL_NPC_LIMIT")){
                HELL_NPC_LIMIT = activityConfigMap.get("HELL_NPC_LIMIT").getIntValue();
            }
            if(activityConfigMap.containsKey("HELL_COST_NUM")){
                String str = activityConfigMap.get("HELL_COST_NUM").getValue();
                List<Integer> costList = StringUtils.stringToIntegerList(str, ";");
                HELL_COST_ONE = costList.get(0);
                HELL_COST_ONEKEY = costList.get(1);
            }

            if(activityConfigMap.containsKey("HELL_ONEKEY_VIP")){
                HELL_ONEKEY_VIP = activityConfigMap.get("HELL_ONEKEY_VIP").getIntValue();
            }
            if(activityConfigMap.containsKey("HELL_ONEKEY_SCORE")){
                HELL_ONEKEY_SCORE = activityConfigMap.get("HELL_ONEKEY_SCORE").getIntValue();
            }
        }

        npcMap = tempNcpMap;
        qualityMap = tempQualityMap;
        eventMap = tempEventMap;
        ageMap = tempAgeMap;
        activityInfo = tmpActivityInfo;
        reloadPlayerData();
        getLogger().info("reload hell activity end");
    }

    private static void reloadPlayerData() {
        if (ActivityMgr.activityInShowTime(activityInfo)) {
            for (GamePlayer player : GamePlayerMgr.getCopyPlayerMap().values()) {
                if (SystemOpenMgr.systemOpen(player, eSystemId.HellActivity.getValue())) {
                    HellModule module = player.getModule(HellModule.class);
                    module.initUserData(activityInfo.getActivityId());
                    module.syncUserData();
                }
            }
        }
    }

    /**
     * 是否在清空道具时间内
     */
    public static boolean isActivityInClearTime() {
        return ActivityMgr.activityInRewardPeriod(activityInfo);
    }

    /**
     * 获取展示中的活动ID（0表示没活动）
     */
    public static int getShowTimeActivityId() {
        return activityInfo == null ? 0 : activityInfo.getActivityId();
    }

    public static boolean activityInTime(){
        return ActivityMgr.activityInTime(activityInfo);
    }

    public static boolean activityInShowTime(){
        return ActivityMgr.activityInShowTime(activityInfo);
    }

    public static ActivityInfo getActivityInfo() {
        return activityInfo;
    }

}
